/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package algoritmo;

import java.util.List;

/**
 * Representa un nodo genérico, no necesariamente de un grafo, puede ser cualquier
 * problema. Las subclases deben implementar expand(), que nos regresará todos
 * los nodos hijos de este nodo. Las subclases también deben implementar equals()
 * pues están sujetos a comparaciones con otros nodos instanciados durante la 
 * ejecución del algoritmo, que podrían representar el mismo nodo.
 * 
 */
public abstract class Node {
    
    /*
     * Apuntador al nodo del cual este nodo fue expandido, para poder reconstruir
     * el camino
     */
    protected Node prev;
    /*
     * Identificador usado en la representación en cadena de este nodo
     */
    protected String id;   
    /*
     * Regresa los hijos de este nodo
     * @return la lista de hijos, los cuales son subclases de Node
     */
    public abstract List<? extends Node> expand();
    /*
     * Regresa el nodo del cual este nodo fue expandido
     * @return el padre o null si no tiene padre
     */
    public Node prev() {
        return prev;
    }
    /*
     * Checa si tiene padre
     * @return el padre o null si no tiene padre
     */
    public boolean hasPrev() {
        return prev != null;
    }
    
    public void setPrev(Node prev) {
        this.prev = prev;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    
    /* Calcula la profundidad a la que se encuentra este nodo, es decir, cuántas
     * veces ha sido expandido
     * @return la profundidad
     */
    public abstract int getDepth();
    
    /*
     * Devuelve la cadena de este nodo, que es una lista encerrada en llaves de toda
     * la ruta que se siguió para llegar a ese nodo. Se usa el id del nodo como
     * representacion.
     * @return la representación en cadena del nodo
     */
    @Override
    public String toString() {
        String s = "{";
        Node ap = this;
        while (ap.hasPrev()) {
            s += ap.id+", ";
            ap = ap.prev();           
        }
        s += ap.id + "}";
        return s;
    }
    
     public void printPath(){
        Node ap = this;
        System.out.println(ap);
        while(ap.hasPrev()){
            ap = ap.prev();
            System.out.println(ap);
        }
    }
    
    /* Regresa el costo asociado al camino para llegar a este nodo
     * La implementación por default es simplemente el número de veces que ha sido
     * expandido
     */
    public int getPathCost(){
        return getDepth();
    }
    
    public Node clone(){
        return clone();
    }
}
